# pylint: disable=broad-except, attribute-defined-outside-init
import logging
import asyncio
from typing import Callable, Dict, List, Union, Type
from src.basedata.application import commands
from src.basedata.common.dep_manage import ENVIRONMENT
from src.basedata.infrastructure.common import unit_of_work

logger = logging.getLogger(__name__)

Message = Union[commands.Command]

@ENVIRONMENT.register('bus')
class MessageBus:
    def __init__(
            self,
            uow: unit_of_work.AbstractUnitOfWork,
            command_handlers: Dict[Type[commands.Command], Callable],
    ):
        self.uow = uow
        self.command_handlers = command_handlers

    async def handle(self, message: Message):
        # logger.info("begin handle...")
        if isinstance(message, commands.Command):
            return await self.handle_command(message)
        else:
            raise TypeError(f"{message} was not an Event or Command")

    async def handle_command(self, command: commands.Command):
        logger.debug("handling command {0}".format(command))
        try:
            handler = self.command_handlers[type(command)]
            return await asyncio.wait_for(handler(command), 200)
        except Exception:
            logger.exception("Exception handling command {0}".format(command))
            raise
